#include "netstm.h"

ByteStream::ByteStream(uint8* buf, uint32 offset, uint32 buf_size)
{
  this->m_buf = buf;
  this->m_cur_pos = offset;
  this->m_buf_size = buf_size;
  m_is_valid_data = true;
}

ByteStream::~ByteStream()
{
}

void ByteStream::Attach(uint8* buf, uint32 offset, uint32 buf_size)
{
  this->m_buf = buf;
  this->m_cur_pos = offset;
  this->m_buf_size = buf_size;
}

uint32 ByteStream::Seek(uint32 pos)
{
  m_cur_pos = pos;
  return pos;
}

uint32 ByteStream::Tell()
{
  return this->m_cur_pos;
}

int ByteStream::UsableBytes()
{
  return m_buf_size - m_cur_pos;
}

uint8* ByteStream::get_buf()
{
  return this->m_buf;
}

void ByteStream::Write(void* data, uint32 length)
{
  if(length == 0) return;
  memmove((uint8*)this->m_buf + this->m_cur_pos, (uint8*)data, length);
  m_cur_pos += length;
}

void ByteStream::Modify(uint32 offset,void* data, uint32 length)
{
  if(length == 0) return;
  memcpy((uint8*)this->m_buf + offset, (uint8*)data, length);
  m_cur_pos += length;
}

void ByteStream::Modify_uint32(uint32 offset,uint32 data)
{
  Swap(&data, sizeof(uint32));
  memcpy((uint8*)this->m_buf + offset, &data, sizeof(uint32));
}


void ByteStream::Read(void* data, uint32 length)
{
  if(length == 0) 
  {
    return;
  }
  if(data == NULL)
  {
    return;
  }
  //NEOBS_DETECT_OVERFLOW(length)
  if(m_is_valid_data == false)  
  {
    return;                               
  }
  if(m_cur_pos + length > m_buf_size)          
  {                                       
    m_is_valid_data = false;   
    return;                               
  }                                       

  try
  {
      memcpy((uint8*)data, this->m_buf + this->m_cur_pos, length);
  }
  catch(...)
  {
    return;
  }
  this->m_cur_pos += length;
}

ByteStream& ByteStream::operator << (uint8 ch)
{
  int length = 1;
  
  if(m_is_valid_data == false)
    return *this;

  if(m_cur_pos + length > m_buf_size)
  {
    m_is_valid_data = false;
    return *this;
  }
  
  this->m_buf[m_cur_pos] = ch;
  this->m_cur_pos += length;
  return *this;
}

ByteStream& ByteStream::operator << (uint16 s)
{
  Swap(&s, sizeof(uint16));
  Write(&s, sizeof(uint16));
  return *this;
}

ByteStream& ByteStream::operator << (uint32 l)
{
  Swap(&l, sizeof(uint32));
  Write(&l, sizeof(uint32));
  return *this;
}

ByteStream& ByteStream::operator << (char* str)
{
  if(str)
  {
    uint16 len = strlen(str);
    (*this) << len;
    if(len > 0)
      Write((void*)str, len);
  }
  else
  {
    uint16 len = 0;
    (*this) << len;
  }

  return *this;
}

ByteStream& ByteStream::operator << (const char str[])
{
  if(str)
  {
    uint16 len = strlen(str);
    (*this) << len;
    if(len > 0)
      Write((void*)str, len);
  }
  else
  {
    uint16 len = 0;
    (*this) << len;
  }

  return *this;
}

ByteStream& ByteStream::operator >> (uint8& ch)
{
  int length = 1;

  if(m_is_valid_data == false)
    return *this;
  if(m_cur_pos + length > m_buf_size)
  {
    m_is_valid_data = false;
    return *this;
  }

  ch = this->m_buf[m_cur_pos];
  this->m_cur_pos += length;
  return *this;
}

ByteStream& ByteStream::operator >> (char& ch)
{
  int length = 1;

  if(m_is_valid_data == false)
    return *this;
  if(m_cur_pos + length > m_buf_size)
  {
    m_is_valid_data = false;
    return *this;
  }

  ch = this->m_buf[m_cur_pos];
  this->m_cur_pos += length;
  return *this;
}

ByteStream& ByteStream::operator >> (uint16& s)
{
  Read(&s, sizeof(uint16));
  Swap(&s, sizeof(uint16));
  return *this;
}

ByteStream& ByteStream::operator >> (uint32& l)
{
  Read(&l, sizeof(uint32));
  Swap(&l, sizeof(uint32));
  return *this;
}

ByteStream& ByteStream::operator >> (char*& str)
{
  uint16 len = 0;
  (*this) >> len;

  if(len > 0)
  {
    if(str)
    {
      Read((void*)str, len);

      if(is_valid_data())
        str[len] = 0;
      else
        str[0] = 0;
    }
    else
    {
      str = new char[len + 1];
      Read((void*)str, len);

      if(is_valid_data())
        str[len] = 0;
      else
        str[0] = 0;
    }
  }
  else
  {
    if(str)
      str[0] = 0;
  }

  return *this;
}

// memory needs to be released after using
char* ByteStream::ReadString(uint16 max_len)
{
  char* str = NULL;
  uint16 len = 0;
  (*this) >> len;
  if(len > 0)
  {
    str = new char[len + 1];
    Read((void*)str, len);

    if(is_valid_data())
      str[len] = 0;
    else
      str[0] = 0;
  }

  return str;
}

void ByteStream::ReadString(char* str, uint16 max_len)
{
  str[0] = 0;

  uint16 len = 0;
  (*this) >> len;
  
  if(len > 0)
  {
    Read((void*)str, len);

    if(is_valid_data())
      str[len] = 0;
    else
      str[0] = 0;
  }
}
void ByteStream::Swap(void* data, int length)
{
	uint8* pch = (uint8*)data;

	for(int i = 0; i < length / 2; i++)
	{
	  uint8 ch_temp;
	  ch_temp = pch[i];
	  pch[i] = pch[length-1-i];
	  pch[length-1-i] = ch_temp;
	}
}
